﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace Utilities
{
    /// <summary>
    /// Some utilities to help dealing with text files.
    /// </summary>
    public static class FileIO
    {
        public class FileIteratorStreamer : IEnumerable<string>
        {
            private FileInfo _file;

            public FileIteratorStreamer(FileInfo f)
            {
                _file = f;
            }

            public System.Collections.Generic.IEnumerator<string> GetEnumerator()
            {
                using (TextReader rdr = _file.OpenText())
                {
                    string line = "";
                    while (line != null)
                    {
                        line = rdr.ReadLine();
                        if (line != null)
                        {
                            yield return line;
                        }
                    }
                    rdr.Close();
                }
            }

            #region IEnumerable Members

            System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
            {
                return GetEnumerator();
            }

            #endregion
        }

        public static FileIteratorStreamer GetLineIterator(this FileInfo file)
        {
            return new FileIteratorStreamer(file);
        }

        /// <summary>
        /// Copies the given file to a temp file. File extension remains the same.
        /// </summary>
        /// <param name="file"></param>
        /// <returns></returns>
        public static FileInfo CopyToTempFile(this FileInfo file)
        {
            FileInfo result = new FileInfo(Path.GetTempFileName() + file.Extension);
            file.CopyTo(result.FullName, true);
            result.Refresh();
            return result;
        }

        /// <summary>
        /// Write out a file that contains a single line of text.
        /// </summary>
        /// <param name="file"></param>
        /// <param name="line"></param>
        public static void WriteSingleLine(this FileInfo file, string line)
        {
            using (TextWriter wr = file.CreateText())
            {
                wr.WriteLine(line);
                wr.Close();
            }
        }

        /// <summary>
        /// Return the first line of a file.
        /// </summary>
        /// <param name="file"></param>
        /// <returns></returns>
        public static string GetFirstLine(this FileInfo file)
        {
            using (TextReader rdr = file.OpenText())
            {
                string result = rdr.ReadLine();
                rdr.Close();
                return result;
            }
        }

        /// <summary>
        /// Open file for appending. If directory hasn't been created, then create it.
        /// If file hasn't been created, then make sure it gets created too.
        /// </summary>
        /// <param name="file"></param>
        /// <returns></returns>
        public static TextWriter CreateAppendForce(this FileInfo file)
        {
            if (!file.Directory.Exists)
            {
                file.Directory.Create();
            }
            return new StreamWriter(file.Open(FileMode.Append, FileAccess.Write));
        }

        /// <summary>
        /// Scan a text file and everywhere you find findText, replace it with replaceText.
        /// Currently optimized for small files (file is read into memory!).
        /// An exception could mean that the file is lost.
        /// </summary>
        /// <param name="file"></param>
        /// <param name="findText"></param>
        /// <param name="replaceText"></param>
        public static void ReplaceText(this FileInfo file, string findText, string replaceText)
        {
            var modified = from l in file.GetLineIterator()
                           select l.Replace(findText, replaceText);
            var lines = modified.ToArray();

            using (TextWriter wr = file.CreateText())
            {
                foreach (string l in lines)
                {
                    wr.WriteLine(l);
                }
                wr.Close();
            }
        }

        /// <summary>
        /// Insert a string as the new first line at the start of a text file.
        /// </summary>
        /// <param name="file"></param>
        /// <param name="newFirstLine"></param>
        public static void InsertAsFirstLine(this FileInfo file, string newFirstLine)
        {
            var lines = file.GetLineIterator().ToArray();
            using (StreamWriter wr = new StreamWriter (file.FullName, false, Encoding.UTF8))
            {
                wr.WriteLine(newFirstLine);
                foreach (var l in lines)
                {
                    wr.WriteLine(l);
                }
                wr.Close();
            }
        }
    }
}
